package es.ull.opendata.px2scovo.pcaxis.px;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import es.ull.opendata.px2scovo.pcaxis.fileparser.PXParser;
import es.ull.opendata.px2scovo.pcaxis.fileparser.PXParserException;

public class PX {

	Logger logger = LoggerFactory.getLogger(this.getClass());

	private String title;
	private String subjectArea;
	private String subjectCode;
	private String description;
	private String survey;// correspondería al dataset.
	private String source;// es la fuente.
	private List<Variable> variables; // corresponde con dimension.
	private List<String> data;// corresponde con los items

	private String getFilename(String sourceName) throws IOException {

		try {
			URL urlFile = new URL(sourceName);
			
			File tmpFile = File.createTempFile("pxFile_", ".px");

			FileWriter tmpFilewriter = new FileWriter(tmpFile);
			PrintWriter pwTmpFile = new PrintWriter(tmpFilewriter);
			BufferedReader brTmpFile = new BufferedReader(
					new InputStreamReader(urlFile.openStream(),
							PXParser.PXENCODING));
			String str;
			while ((str = brTmpFile.readLine()) != null) {
				pwTmpFile.println(str);
			}
			tmpFilewriter.close();

			return tmpFile.getAbsolutePath();
		} catch (MalformedURLException e) {
			return sourceName;
		}
	}

	public PX(String sourceName) throws PXException, IOException {
		variables = new ArrayList<Variable>();
		data = new ArrayList<String>();
		title = "";
		subjectArea = "";
		subjectCode = "";
		description = "";
		survey = "";
		source = "";
		loadPX(sourceName);
	}

	public PX() {
		variables = new ArrayList<Variable>();
		data = new ArrayList<String>();
		title = "";
		subjectArea = "";
		subjectCode = "";
		description = "";
		survey = "";
		source = "";
	}

	public boolean isValidPX() {
		if ((StringUtils.isBlank(title)) || (StringUtils.isBlank(subjectArea))
				|| (StringUtils.isBlank(subjectCode))
				|| (StringUtils.isBlank(description))
				|| (StringUtils.isBlank(survey))
				|| (StringUtils.isBlank(source))) {
			return false;
		}
		if (variables.size() == 0) {
			return false;
		}
		int numberOfDatas = 1;
		for (int i = 0; i < variables.size(); i++) {
			List<Category> categories = variables.get(i).getCategories();
			if (categories.size() == 0) {
				return false;
			}
			numberOfDatas *= categories.size();
		}
		if (data.size() != numberOfDatas) {
			return false;
		}
		return true;
	}

	public void clear() {
		title = "";
		subjectArea = "";
		subjectCode = "";
		description = "";
		survey = "";
		source = "";
		variables.clear();
		data.clear();

	}

	public void savePX(String filename) throws IOException {
		FileWriter fileOut = new FileWriter(filename);
		PrintWriter pw = new PrintWriter(fileOut);
		pw.println("TITLE=\"" + title + "\"");
		pw.println("SUBJECT-AREA=\"" + subjectArea + "\"");
		pw.println("SUBJECT-CODE=\"" + subjectCode + "\"");
		pw.println("DESCRIPTION=\"" + description + "\"");
		pw.println("SURVEY=\"" + survey + "\"");
		pw.println("SOURCE=\"" + source + "\"");

		// Next insert the VALUES
		for (int i = 0; i < variables.size(); i++) {
			Variable variable = variables.get(i);
			pw.print("VALUES(\"" + variable.getName() + "\")=");
			List<Category> categories = variable.getCategories();
			for (int j = 0; j < categories.size() - 1; j++) {
				pw.print("\"" + categories.get(j).getName() + "\",");
			}
			pw.print("\"" + categories.get(categories.size() - 1).getName()
					+ "\";\n");
		}

		// Next insert the CODES
		for (int i = 0; i < variables.size(); i++) {
			Variable variable = variables.get(i);
			pw.print("CODES(\"" + variable.getName() + "\")=");
			List<Category> categories = variable.getCategories();
			for (int j = 0; j < categories.size() - 1; j++) {
				pw.print("\"" + categories.get(j).getCode() + "\",");
			}
			pw.print("\"" + categories.get(categories.size() - 1).getCode()
					+ "\";\n");
		}

		// Next we insert the DATA
		pw.print("DATA=");
		for (int i = 0; i < data.size() - 1; i++) {
			pw.print(data.get(i) + " ");
		}
		pw.print(data.get(data.size() - 1) + " ;");
		pw.close();
		fileOut.close();
	}

	@SuppressWarnings("unchecked")
	public void loadPX(String filename) throws PXException, IOException {
		File fileIn = new File(getFilename(filename));

		if (!fileIn.exists()) {
			throw new FileNotFoundException();
		}
		PXParser pxParser = new PXParser(fileIn);
		try {
			Map<String, Object> parseMap = pxParser.parseFile();
			// Next, we get the attributes
			title = (String) parseMap.get("TITLE");
			subjectArea = (String) parseMap.get("SUBJECT-AREA");
			subjectCode = (String) parseMap.get("SUBJECT-CODE");
			description = (String) parseMap.get("DESCRIPTION");
			survey = (String) parseMap.get("SURVEY");
			source = (String) parseMap.get("SOURCE");
			data = (List<String>) parseMap.get("DATA");
			// We do the variables

			// FIRST, WE DO THE VALUES
			LinkedHashMap<String, ArrayList<String>> values = (LinkedHashMap<String, ArrayList<String>>) parseMap.get("VALUES");
			Iterator<String> valuesIt = values.keySet().iterator();
			while (valuesIt.hasNext()) {
				Variable variable = new Variable();
				String keyValue = (String) valuesIt.next();
				ArrayList<String> valueValue = values.get(keyValue);
				ArrayList<Category> categories = new ArrayList<Category>();
				for (int i = 0; i < valueValue.size(); i++) {
					Category category = new Category();
					category.setCode("");
					category.setName(valueValue.get(i));
					categories.add(category);
				}
				variable.setName(keyValue);
				variable.setCategories(categories);
				variables.add(variable);
			}
			
			// NEXT, WE DO THE CODES
			LinkedHashMap<String, ArrayList<String>> codes = (LinkedHashMap<String, ArrayList<String>>) parseMap.get("CODES");
			Iterator<String> codesIt = codes.keySet().iterator();
			while (codesIt.hasNext()) {
				String keyCode = (String) codesIt.next();
				ArrayList<String> valueCode = codes.get(keyCode);
				for (Variable variable : variables) {
					if (variable.getName().equals(keyCode)) {
						List<Category> categories = variable.getCategories();
						for (int i = 0; i < valueCode.size(); i++) {
							categories.get(i).setCode(valueCode.get(i));
						}
					}
				}
			}
		} catch (PXParserException e) {
			logger.error("Error when parsing Px File", e);
			throw new PXException(e);
		}
	}

	public List<String> getData() {
		return data;
	}

	public void setData(List<String> data) {
		this.data = data;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getSource() {
		return source;
	}

	public void setSource(String source) {
		this.source = source;
	}

	public String getSubjectArea() {
		return subjectArea;
	}

	public void setSubjectArea(String subjectArea) {
		this.subjectArea = subjectArea;
	}

	public String getSubjectCode() {
		return subjectCode;
	}

	public void setSubjectCode(String subjectCode) {
		this.subjectCode = subjectCode;
	}

	public String getSurvey() {
		return survey;
	}

	public void setSurvey(String survey) {
		this.survey = survey;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public List<Variable> getVariables() {
		return variables;
	}

	public void setVariables(List<Variable> variables) {
		this.variables = variables;
	}

}
